﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using SlimDX.Direct3D10;

namespace System.Windows.Media.Media3D10
{
    /// <summary>
    /// <see cref="Model3D10"/> pour une texture d'environnement
    /// </summary>
    public sealed class SkyboxModel3D10 : RenderModel3D10
    {
        #region Dependency Properties
        /// <summary>
        /// Identifie la propriété de dépendance <see cref="Map"/>.
        /// </summary>
        public static readonly DependencyProperty MapProperty =
            DependencyProperty.Register("Map", typeof(CubeMap), typeof(SkyboxModel3D10),
            new PropertyMetadata(new PropertyChangedCallback(Map_PropertyChanged)));
        #endregion

        #region Dependency Properties Callbacks
        private static void Map_PropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(sender, null))
                throw new ArgumentNullException("sender");
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
            (sender as SkyboxModel3D10).OnMapChanged(e);
        }
        #endregion

        #region Data
        private static readonly MeshGeometry3D10 _geometry = CubeTesselator.Tessellate(2.0f);
        private const string g_EnvironmentTexture = "g_EnvironmentTexture";
        private EffectResourceVariable _brushVariable;
        #endregion

        #region Public Properties
        /// <summary>
        /// Texture d'environnement
        /// </summary>
        public CubeMap Map
        {
            get { return (CubeMap)GetValue(MapProperty); }
            set { SetValue(MapProperty, value); }
        }
        #endregion

        #region Private Methods
        private void OnMapChanged(DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
            //if (_brushVariable != null) _brushVariable.SetTexture(this.Map.GetTextureCube());
        }
        #endregion

        #region Model3D10 Overrides
        /// <summary>
        /// Appelée lors du changement de l'effet
        /// </summary>
        /// <param name="e"><see cref="DependencyPropertyChangedEventArgs"/> décrivant les informations sur le changement.</param>
        protected override void OnEffectChanged(DependencyPropertyChangedEventArgs e)
        {
            base.OnEffectChanged(e);
            if (this.Effect != null)
            {
                _brushVariable = this.Effect.GetVariableByName(g_EnvironmentTexture).AsResource();
            }
            else
            {
                _brushVariable = null;
            }
        }

        /// <summary>
        /// En cas de substitution dans une classe dérivée, participe au dessin des objets dans le pipeline DirectX10
        /// </summary>
        /// <param name="context">Contexte de dessin.</param>
        /// <exception cref="ArgumentNullException">Soulevée si le contexte est null.</exception>
        protected override void OnDraw(DrawingContext context)
        {
            if (object.ReferenceEquals(context, null))
                throw new ArgumentNullException("context");
            base.OnDraw(context);

            //context.DrawIndexed(this, PrimitiveTopology.TriangleList, _geometry.TriangleIndices);
        }
        #endregion

        #region RenderModel3D10 Implementation
        /// <summary>
        /// Crée le <see cref="InputLayout"/> associé à ce <see cref="RenderModel3D10"/>
        /// </summary>
        /// <returns></returns>
        protected override SlimDX.Direct3D10.InputLayout CreateInputLayoutCore()
        {
            if (this.CurrentEffectTechnique == null || _geometry == null)
                return null;
            return this.CurrentEffectTechnique.CreateInputLayout(_geometry.GetInputElements().Take(1).ToArray());
        }

        /// <summary>
        /// Crée le <see cref="VertexBufferBinding"/> associé à ce <see cref="RenderModel3D10"/>
        /// </summary>
        /// <returns></returns>
        protected override SlimDX.Direct3D10.VertexBufferBinding[] CreateVertexBufferBindingCore()
        {
            if (_geometry == null || !_geometry.IsFrozen)
                return null;
            return _geometry.GetVertexBufferBinding().Take(1).ToArray();
        }
        #endregion

        #region Freezable Implementation
        /// <summary>
        /// Une fois implémentée dans une classe dérivée, initialise une nouvelle instance de la classe dérivée <see cref="Freezable"/>. 
        /// </summary>
        /// <returns>Nouvelle instance.</returns>
        protected override Freezable CreateInstanceCore()
        {
            return new SkyboxModel3D10();
        }
        #endregion
    }
}
